//!
/**
 ***********************************************************************************************************
 * <RBD3D9PixelBuffer Implementation>
 ***********************************************************************************************************
 * @file RBD3D9PixelBuffer.cpp
 ***********************************************************************************************************/

/***********************************************************************************************************
 * Precompiled Header
 ***********************************************************************************************************/
#include "RBD3D9RendererPCH.h"

/***********************************************************************************************************
 * Includes
 ***********************************************************************************************************/
#include "RBD3D9PixelBuffer.h"

#include "RBD3D9Renderer.h"
#include "RBD3D9Tools.h"
#include <RBMain/RBTexture.h>

/***********************************************************************************************************
 * Defines
 ***********************************************************************************************************/

/***********************************************************************************************************
 * Classes implementation
 ***********************************************************************************************************/



/***********************************************************************************************************
 *
 ***********************************************************************************************************/
RBD3D9PixelBuffer::RBD3D9PixelBuffer(uint32 uiUsage, uint32 uiMemPoolMask, RBHardwareBufferManager* pCreator, uint32 uiWidth, uint32 uiHeight, RBPixelFormat eFormat, 
                                     uint32 uiMSAA, RBTexture* pContainer, bool bCreateSurface)
: RBPixelBuffer(uiUsage, uiMemPoolMask, pCreator, uiWidth, uiHeight, eFormat, uiMSAA, pContainer)
, m_pD3DSurface(NULL)
, m_bOwned(false)
{
    if (bCreateSurface)
    {
        CreateSurface();
        m_bOwned = true;
    }
}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
RBD3D9PixelBuffer::~RBD3D9PixelBuffer()
{
    RBCommon::SafeRelease(m_pD3DSurface);
}

/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
RBPixelBuffer::MappedBuffer RBD3D9PixelBuffer::Map( MapType eMapType )
{
    RBPixelBuffer::MappedBuffer result;
    result.Data = NULL;
    result.Pitch = 0;
    D3DLOCKED_RECT d3dLockedRect;
    if (SUCCEEDED(m_pD3DSurface->LockRect(&d3dLockedRect, NULL, RBD3D9Tools::ComputeD3DMapFlagsFromRB(eMapType, this))))
    {
        result.Data = d3dLockedRect.pBits;
        result.Pitch = d3dLockedRect.Pitch;
    }
    return result;
}


/***********************************************************************************************************
 * 
 ***********************************************************************************************************/
void RBD3D9PixelBuffer::Unmap()
{
    m_pD3DSurface->UnlockRect();
}

void RBD3D9PixelBuffer::OnReset(bool bBeforeReset)
{
    if (!(m_uiMemPoolMask & MP_CPU))
    {
        if (bBeforeReset)
        {
            RBCommon::SafeRelease(m_pD3DSurface);
            m_pD3DSurface = 0;
        }
        else if (m_bOwned)
        {
            // We must re-create data
            CreateSurface();
        }
    }

}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
void RBD3D9PixelBuffer::CreateSurface()
{
    D3DMULTISAMPLE_TYPE d3dMS;
    DWORD d3dMSQuality;
    RBD3D9Tools::ComputeD3DMSAA(m_uiMSAA, d3dMS, d3dMSQuality);
    if (m_uiUsage & RBTexture::HBU_DEPTHSTENCIL)
    {
        RBD3D9Renderer::GetSingleton()->GetD3DDevice()->CreateDepthStencilSurface(m_uiWidth, m_uiHeight,RBD3D9Tools::ComputeD3DFormat(m_ePixelFormat), d3dMS, d3dMSQuality, true, &m_pD3DSurface, NULL);
    }
    else if (m_uiUsage & RBTexture::HBU_GPUWRITE)
    {
        RBD3D9Renderer::GetSingleton()->GetD3DDevice()->CreateRenderTarget(m_uiWidth, m_uiHeight,RBD3D9Tools::ComputeD3DFormat(m_ePixelFormat), d3dMS, d3dMSQuality, false, &m_pD3DSurface, NULL);
    }
}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
void RBD3D9PixelBuffer::SetSurface(IDirect3DSurface9* pD3DSurface)
{
    if (pD3DSurface != m_pD3DSurface)
    {
        RBCommon::SafeRelease(m_pD3DSurface);
        m_pD3DSurface = pD3DSurface;
        m_uiHeight = 0;
        m_uiWidth = 0;
        if (m_pD3DSurface)
        {
            m_pD3DSurface->AddRef();
            D3DSURFACE_DESC d3dSurfDesc;
            if (SUCCEEDED(m_pD3DSurface->GetDesc(&d3dSurfDesc)))
            {
                m_uiWidth = d3dSurfDesc.Width;
                m_uiHeight = d3dSurfDesc.Height;
            }
        }
    }

}

/***********************************************************************************************************
 *
 ***********************************************************************************************************/
void RBD3D9PixelBuffer::Resize(uint32 uiWidth, uint32 uiHeight)
{
    Super::Resize(uiWidth, uiHeight);
}


/***********************************************************************************************************
 *
 ***********************************************************************************************************/
void RBD3D9PixelBuffer::Blit(RBPixelBuffer* pDest, float2 srcStart, float2 srcEnd, float2 dstStart, float2 dstEnd) const
{
    RBD3D9PixelBuffer* pRealDest = static_cast<RBD3D9PixelBuffer*>(pDest);
    if (m_uiMemPoolMask == MP_GPU && pDest->GetMemPool() == MP_GPU)
    {
        RECT srcRect, dstRect;
        srcRect.left    = static_cast<uint32>(srcStart.x * GetWidth());
        srcRect.right   = static_cast<uint32>(srcEnd.x   * GetWidth());
        srcRect.top     = static_cast<uint32>(srcStart.y * GetHeight());
        srcRect.bottom  = static_cast<uint32>(srcEnd.y   * GetHeight());
        dstRect.left    = static_cast<uint32>(dstStart.x * GetWidth());
        dstRect.right   = static_cast<uint32>(dstEnd.x   * GetWidth());
        dstRect.top     = static_cast<uint32>(dstStart.y * GetHeight());
        dstRect.bottom  = static_cast<uint32>(dstEnd.y   * GetHeight());
        RBD3D9Renderer::GetSingleton()->GetD3DDevice()->StretchRect(GetSurface(), &srcRect, pRealDest->GetSurface(), &dstRect, D3DTEXF_NONE);
    }
    else if (m_uiMemPoolMask == MP_GPU && pDest->GetMemPool() == MP_CPU)
    {
        RBAssert(m_uiMSAA == 0,"");
        RBAssert(m_uiWidth == pRealDest->m_uiWidth,"");
        RBAssert(m_uiHeight == pRealDest->m_uiHeight,"");
        RBAssert(m_ePixelFormat == pRealDest->m_ePixelFormat,"");
        RBD3D9Renderer::GetSingleton()->GetD3DDevice()->GetRenderTargetData(GetSurface(), pRealDest->GetSurface());
    }

}
